package com.momoc.netty.frame.session;

import com.google.protobuf.MessageLiteOrBuilder;
import com.momoc.netty.frame.config.CleanClientConnectResources;
import com.momoc.netty.frame.dispatch.WebsocketRequestContextHolder;
import com.momoc.netty.frame.event.annotation.WebsocketCloseEvent;
import com.momoc.netty.frame.event.annotation.WebsocketConnectEvent;
import com.momoc.netty.frame.event.annotation.WebsocketEvent;
import com.momoc.netty.frame.session.vo.UserSessionInfo;
import io.netty.buffer.Unpooled;
import io.netty.channel.Channel;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelId;
import io.netty.handler.codec.http.websocketx.BinaryWebSocketFrame;
import io.netty.handler.codec.http.websocketx.CloseWebSocketFrame;
import io.netty.handler.codec.http.websocketx.WebSocketFrame;
import java.util.Collection;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import lombok.extern.slf4j.Slf4j;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * aurora
 *
 * 使用时需要实现当前会话管理器
 * 会话管理器，父类记得加上  {@link WebsocketEvent}注解
 * @author momoc
 * @version 1.0
 * @className SessionManagerContext
 * @description
 * @date 2023/7/5 18:17
 */
public abstract class SessionManagerAbstract<T> {

    static Logger log = LoggerFactory.getLogger(CleanClientConnectResources.class);

    /**
     * 当前实例所有的会话channel
     *
     */
    protected Map<String, UserSessionInfo<T>> sessionInfoMap = new ConcurrentHashMap<>();


    @WebsocketConnectEvent
    public void connect(Channel channel){
        ChannelId id = channel.id();
        String token = id.asShortText();
        UserSessionInfo<T> userSessionInfo = new UserSessionInfo<T>();
        userSessionInfo.setChannel(channel);
        sessionInfoMap.put(token, userSessionInfo);
        connectAfter(channel);
    }

    /**
     * 建立链接后调用
     * @param channel
     */
    public abstract void connectAfter(Channel channel);



    @WebsocketCloseEvent
    public void close(Channel channel) {
        log.info("websocket关闭事件2:{}", channel);
        String token = channel.id().asShortText();
        UserSessionInfo<T> remove = sessionInfoMap.remove(token);
        closeConnectAfter(remove);

    }


    /**
     * 关闭连接后调用
     * @param userSessionInfo
     */
    public abstract void closeConnectAfter(UserSessionInfo<T> userSessionInfo);

    /**
     * 给当前实例所有用户发送消息
     * @param messageLiteOrBuilder
     */

    public void sendMsgAllUser(MessageLiteOrBuilder messageLiteOrBuilder){
        for (UserSessionInfo<T> value : sessionInfoMap.values()) {
            Channel channel = value.getChannel();
            channel.writeAndFlush(messageLiteOrBuilder);
        }
    }


    /**
     * 通过tokenWs发送消息给用户
     * @param tokenWs 唯一链接id
     * @param bytes 已经编码的消息
     */

    public void sendMsgToUserByTokenWs(String tokenWs, byte[] bytes){
        UserSessionInfo<T> tUserSessionInfo = sessionInfoMap.get(tokenWs);
        if (tUserSessionInfo != null) {
            Channel channel = tUserSessionInfo.getChannel();
            WebSocketFrame frame = new BinaryWebSocketFrame(Unpooled.wrappedBuffer(bytes));
            channel.writeAndFlush(frame);
        }

    }



    /**
     * 获取会员会话数据
     *
     * @return
     */
    public  UserSessionInfo<T> getUserSessionInfo(){
        ChannelHandlerContext requestChannel = WebsocketRequestContextHolder.getRequestChannel();
        Channel channel = requestChannel.channel();
        return sessionInfoMap.get(channel.id().asShortText());
    }

    public  UserSessionInfo<T> getUserSessionInfo(String tokenWs){
        return sessionInfoMap.get(tokenWs);
    }


    /**
     * 清理用户资源
     * @return
     */
    public void clearAllUserSessionInfo(){

//        Collection<UserSessionInfo<T>> values = sessionInfoMap.values();
//
//        beforeClearAllSessionIfo(values);
//
//        for (UserSessionInfo<T> value : values) {
//            log.info("close client connect :{}", value.getChannel().id().asShortText());
//            Channel channel = value.getChannel();
//            //关闭链接后，会发送关闭信号给前端
//            channel.writeAndFlush(new CloseWebSocketFrame());
//            channel.close();
//        }
//        return true;
    }

    /**
     * 清理资源前的操作，无法操作redis等链接，因为已经释放掉了
     * @param values
     */
     protected abstract void beforeClearAllSessionIfo(Collection<UserSessionInfo<T>> values);


}
